<?php
declare (strict_types=1);

namespace app\command;

use app\command\install\Fuc;
use app\exception\BaseException;
use app\model\Admin;
use stdClass;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Exception;
use think\facade\View;
use think\Request;

/**
 * 安装执行命令
 * Class Install
 * @package app\command
 */
class Install extends Command
{
    protected function configure()
    {
        $config = config('database.connections.mysql');
        // 指令配置,因为shirtcut只能定义一个字母不好用
        $this->setName('install')
            ->addOption('hostname', 'e', Option::VALUE_OPTIONAL, 'mysql hostname', $config['hostname'])
            ->addOption('hostport', 't', Option::VALUE_OPTIONAL, 'mysql hostport', $config['hostport'])
            ->addOption('database', 'd', Option::VALUE_OPTIONAL, 'mysql database', $config['database'])
            ->addOption('username', 'u', Option::VALUE_OPTIONAL, 'mysql username', $config['username'])
            ->addOption('password', 'p', Option::VALUE_OPTIONAL, 'mysql password', $config['password'])
            ->addOption('prefix', 'x', Option::VALUE_OPTIONAL, 'table prefix', $config['prefix'])
            ->addOption('force', 'f', Option::VALUE_OPTIONAL, 'force override', false)
            ->setDescription('数据库安装');
    }


    protected function execute(Input $input, Output $output)
    {
        #1、是否已经安装
        // 覆盖安装
        $force = $input->getOption('force');
        $lockFile = public_path() . 'install.lock';

        if (file_exists($lockFile) && !$force) {
            $output->error("\n[Error]\nalready installed!If you need to reinstall again, use the parameter --force=true ");
            exit();
        }

        #2、检测环境
        $output->writeln('正在检测环境...');
        $this->checkenv();
        $output->writeln('检测通过');

        $con = new stdClass();
        $con->hostname = $input->getOption('hostname');
        $con->hostport = $input->getOption('hostport');
        $con->database = $input->getOption('database');
        $con->prefix = $input->getOption('prefix');
        $con->username = $input->getOption('username');
        $con->password = $input->getOption('password');

        $result = $this->install($con);

        if ($result !== 1) {
            $output->error('install faild' . $result . "\n");
        } else {
            $output->info('install success' . "\n");
            //输入管理员名称和密码
            $output->write("Admin username:admin");
            $output->write("Admin password:123456");
        }
    }

    //检测环境
    private function checkenv()
    {
        // 检测目录是否存在
        $checkDirs = [
            'vendor',
        ];

        if (version_compare(PHP_VERSION, '7.1.0', '<')) {
            throw new  BaseException("version %s is too low, please use PHP 7.1.0 or higher", PHP_VERSION);
        }

        if (!extension_loaded("PDO")) {
            throw new BaseException("PDO is not currently installed and cannot be installed");
        }

        foreach ($checkDirs as $k => $v) {
            if (!is_dir(root_path() . $v)) {
                throw new BaseException('dir %s is not exist', $v);
                break;
            }
        }
        return true;
    }

    //pc端安装
    public function index(Request $request)
    {
        $err = '';
        if ($request->isPost()) {
            $adminInfo['username'] = $request->param('username', 'admin');
            $pwd = $request->param('password');
            if ($request->param('passwordConfirm') != $pwd) {
                return json(['code' => 0, 'message' => '两次密码不一致']);
            }
            $adminInfo['email'] = $request->param('email');


            //安装操作
            $con = new stdClass();
            $con->hostname = $request->param('hostname', '127.0.0.1');
            $con->hostport = $request->param('hostport', '3306');
            $con->database = $request->param('database');
            $con->prefix = $request->param('prefix');
            $con->username = $request->param('dbname');
            $con->password = $request->param('dbpassword');

            $result = $this->install($con);
            if ($result === 1) {
                //修改admin密码
                $admin = Admin::getInstance();
                $adminInfo['salt'] = substr(md5(uniqid()), 0, 6);
                $adminInfo['password'] = md5(md5($pwd) . $adminInfo['salt']);
                $admin->renew($adminInfo, ['id' => 1], [], '');
                return json(['code' => 1, 'message' => '安装成功','adminName'=>'index']);
            }
            return json(['code' => 0, 'message' => $result]);
        } else {
            \think\facade\Lang::load(INSTALL_PATH . 'zh-cn.php');
            return View::fetch(INSTALL_PATH . "install.html", ['errInfo' => $err]);
        }
    }


    private function install($con)
    {
        try {
            #1、重载config的database属性或者重写；第4步 db函数需要
            //$database = include config_path().'database.php';  //为了重载，不能用include_once
            //config($database);  //覆盖框架加载时的config；
            $datebase = config('database');
            foreach ($con as $k => $v) {
                if (key_exists($k, $datebase['connections']['mysql'])) {
                    $datebase['connections']['mysql'][$k] = $v;
                }
            }

            config(['database' => $datebase]); //设置时，必须带上标识，且必须是数组

            #2、执行数据库安装功能
            Fuc::initSql(app_path() . 'command/install/init.sql', true);

            #3、生成env文件
            $exampleFile = root_path() . '.example.env';
            $conf = parse_ini_file($exampleFile, true);
            $conf['DATABASE']['HOSTNAME'] = $con->hostname;
            $conf['DATABASE']['DATABASE'] = $con->database;
            $conf['DATABASE']['USERNAME'] = $con->username;
            $conf['DATABASE']['PASSWORD'] = $con->password;
            $conf['DATABASE']['HOSTPORT'] = $con->hostport;
            $conf['DATABASE']['PREFIX'] = $con->prefix;
            $ini = arr2ini($conf);
            $rootPath = root_path();
            file_put_contents($rootPath . '.env', $ini);

            #4.创建lock文件
            file_put_contents(public_path() . 'install.lock', '');
            //成功
            return 1;
        } catch (Exception $e) {
            //失败
            return $e->getMessage();
        }
    }

}
